package com.yidont.douyinhelper

import android.accessibilityservice.AccessibilityService
import android.view.accessibility.AccessibilityNodeInfo
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import com.yidont.douyinhelper.data.configData
import com.yidont.douyinhelper.data.followBean
import com.yidont.douyinhelper.ui.LogWindow
import com.yidont.douyinhelper.util.loge
import kotlinx.coroutines.*

class FollowHelper(private val service: AccessibilityService) {

    private var running = false
    private val scope = MainScope()
    private var job: Job? = null
    private var logWindow: LogWindow? = null
    private var nodeInfo: AccessibilityNodeInfo? = null

    fun run(logWindow: LogWindow, nodeInfo: AccessibilityNodeInfo) {
        this.nodeInfo = nodeInfo
        if (running) return
        running = true
        this.logWindow = logWindow

        launch()
    }

    private fun launch() {
        job?.cancel("取消异常")
        job = scope.launch {
            try {
                val rv = followRv()
                actionItem(rv)
                actionUserProfile()
                actionVideo()

                running = false
            } catch (e: Exception) {
                loge("协程终止", e)
                if (e is TimeoutCancellationException) {
                    running = false
                    log("运行超时请重回粉丝页")
                } else if (e is CancellationException) {
                    val text = e.message
                    log(text)
                    if (text == "重复开始") {
                        log("此用户已完成")
//                        running = true
                        launch()
                    } else {
                        running = false
                    }
                } else {
                    running = false
                }
            }
        }
    }

    private suspend fun followRv() = action {
        nodeInfo.findId("com.ss.android.ugc.aweme:id/l5o").also {
            if (it == null) {
                log("请手动打开指定作者粉丝页")
            } else {
                log("当前是粉丝页面")
            }
        }
    }

    /**
     * 找到需要关注的item
     */
    private suspend fun actionItem(rv: AccessibilityNodeInfo) = action {
        val item = rv.getChild(followBean.index)
        val text = item.findId("com.ss.android.ugc.aweme:id/a7b")?.text.toString()
        when {
            followBean.index >= rv.childCount - 1 -> {
                if (action { rv.scrollForward() }) {
                    followBean.index = 0
                    cancelReStart()
                } else false
            }
            text == "关注" -> {
                action {
                    item.click().takeIf { it }.also { log("第${followBean.index}个") }
                }
            }
            text == "已关注" || text == "已请求" || item.hasText("进入他的主页")/*自己*/ -> {
                followBean.index++
                cancelReStart()
            }
            else -> false
        }
    }

    private suspend fun actionUserProfile() {
        if (followBean.videoOrFollow == 1) {
            // 观看视频
            action {
                val noVideo = nodeInfo.hasText("作品 0")
                val privacy = nodeInfo.hasText("关注帐号即可查看内容和喜欢")
                val hasVideo = nodeInfo.findId("com.ss.android.ugc.aweme:id/inx")
                when {
                    hasVideo != null -> {
                        hasVideo.click().also { if (it) log("开始浏览视频 10秒") }
                    }
                    noVideo -> {
                        log("作品 0")
                        if (followBean.skipVideo0) skipUser() else followUser()
                    }
                    privacy -> {
                        log("私密账号")
                        if (followBean.skipPrivacy) skipUser() else followUser()
                    }
                    else -> {
                        log("未知界面内容")
                        skipUser()
                    }
                }
            }
        } else {
            followUser()
        }
    }

    /**
     * 关注用户
     */
    private suspend fun followUser() {
        delay(1000)
        log("关注用户")
        val follow = action { nodeInfo.findId("com.ss.android.ugc.aweme:id/k05") }
        if (follow.text.toString() == "关注") {
            if (action { follow.click() }) {
                followBean.index++
                log("关注成功，休息 5秒")
                delay(5000)
            }
        }
        action { back() }
        cancelReStart()
    }

    /**
     * 跳过用户
     */
    private suspend fun skipUser() {
        followBean.index++
        delay(1000)
        log("跳过此用户，休息 5秒")
        delay(5000)
        action { back() }
        cancelReStart()
    }

    private suspend fun actionVideo() {
        delay(8000)
        // 点赞
        log("开始点赞")
        val node1 = action { nodeInfo.findId("com.ss.android.ugc.aweme:id/c_v") }
        if (node1.hasText("未点赞")) {
            action { node1.click() }
        }
        // 评论
        log("评论")
        action { nodeInfo.findId("com.ss.android.ugc.aweme:id/cd-").click() }
        delay(2000)
        action {
            val edit = nodeInfo?.findIdLast("com.ss.android.ugc.aweme:id/cbv")
            val bundle =
                bundleOf(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE to followBean.comment)
            edit?.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, bundle) ?: false
        }
        delay(2000)
        action { nodeInfo.findIdLast("com.ss.android.ugc.aweme:id/cc7").click() }
        log("评论成功")
        action { back() }
        action { back() }
        followUser()
    }

    private fun back() = service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK)

    private fun cancelReStart() {
        throw CancellationException("重复开始")
    }

    private fun log(text: String?) {
        logWindow?.log(text)
    }

    fun stop() {
        job?.cancel()
        running = false
        logWindow = null
        nodeInfo?.recycle()
        nodeInfo = null
        followBean.index = 0
        followBean.videoOrFollow = 1
    }

}

suspend inline fun <T> action(
    timeMillis: Long = if (configData.actionDelay >= 5000) configData.actionDelay * 3 else 15000,
    crossinline action: suspend () -> T?
) = withTimeout(timeMillis) {
    delayTime()
    var t: T? = null
    var finished = false
    while (!finished && configData.showLogWindow.value == true) {
        t = action()
        finished = if (t is Boolean) t else t != null
        if (!finished) delay(1500)
    }
    t!!
}

suspend fun delayTime() = delay(configData.actionDelay)

private fun AccessibilityNodeInfo?.findId(id: String) =
    this?.findAccessibilityNodeInfosByViewId(id)?.firstOrNull()

private fun AccessibilityNodeInfo?.findIdLast(id: String) =
    this?.findAccessibilityNodeInfosByViewId(id)?.lastOrNull()

private fun AccessibilityNodeInfo?.hasText(text: String) =
    this?.findAccessibilityNodeInfosByText(text)?.firstOrNull() != null

private fun AccessibilityNodeInfo?.click() =
    this?.performAction(AccessibilityNodeInfo.ACTION_CLICK) ?: false

private fun AccessibilityNodeInfo?.scrollForward() =
    this?.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) ?: false
